home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 5
/
Apprentice-Release5.iso
/
Source Code
/
C
/
Applications
/
Python 1.3.3
/
stdwin
/
Ports
/
mac
/
draw.c
< prev
next >
Wrap
Text File
|
1995-12-21
|
14KB
|
850 lines
/* MAC STDWIN -- DOCUMENT DRAWING. */
/* Contents of this file:
wchange, wscroll;
wbegindrawing, wenddrawing, _wupdate, wupdate;
text attribute manipulation (internal and external);
text measuring;
text drawing;
coordinate conversion tools;
ordinary drawing;
color stuff.
XXX Should be split, only things used between w{begin,end}drawing
belong here.
BEWARE OF COORDINATE SYSTEMS!
The window's origin is not always the same.
When the aplication isn't drawing (i.e., outside w{begin,end}drawing),
the origin is (0, 0); this is necessary because the control mgr
doesn't like it otherwise.
When the application is drawing, the origin is set to win->(orgh, orgv)
so the drawing primitives don't need to do their own coordinate
transformation.
Routines called while not drawing must do their own transformations.
XXX Routines that may be called any time are in trouble!
(There shouldn't be any.)
*/
#include "macwin.h"
#include <Fonts.h>
#include <Memory.h>
#ifdef __MWERKS__
#define CONSTPATCAST (ConstPatternParam) &
#else
#define CONSTPATCAST /*nothing*/
#endif
COLOR _w_fgcolor = blackColor;
COLOR _w_bgcolor = whiteColor;
static COLOR save_fgcolor, save_bgcolor;
static WINDOW *drawing;
static TEXTATTR drawsaveattr;
static int baseline;
static int lineheight;
/* Avoid name conflicts: */
#define getfinfo getfinfo_
#define wsetstyle wsetstyle_
/* Function prototypes */
STATIC void getwattr _ARGS((GrafPtr port, TEXTATTR *attr));
STATIC void setwattr _ARGS((TEXTATTR *attr));
STATIC void getfinfo _ARGS((void));
/* Patterns -- can't use the QuickDraw globals (sigh) */
static Pattern pat0 = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static Pattern pat25 = {0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44};
static Pattern pat50 = {0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa};
static Pattern pat75 = {0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd};
static Pattern pat100 = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
void
wchange(win, left, top, right, bottom)
WINDOW *win;
int left, top, right, bottom;
{
Rect r;
SetPort(win->w);
if (drawing) dprintf("warning: wchange called while drawing");
makerect(win, &r, left, top, right, bottom);
InvalRect(&r);
}
void
wscroll(win, left, top, right, bottom, dh, dv)
WINDOW *win;
int left, top, right, bottom;
int dh, dv;
{
Rect r;
if (drawing) dprintf("warning: wchange called while drawing");
makerect(win, &r, left, top, right, bottom);
scrollby(win, &r, dh, dv);
}
/* Scroll a rectangle (given in window coordinates) by dh, dv.
Also used from scroll.c. */
/* XXX need less visible name */
void
scrollby(win, pr, dh, dv)
WINDOW *win;
Rect *pr;
int dh, dv;
{
RgnHandle rgn= NewRgn();
SetPort(win->w);
rmcaret(win);
if (!EmptyRgn(( (WindowPeek)win->w )->updateRgn)) {
RgnHandle ur= NewRgn();
int left, top;
Rect r;
/* Scroll the part of the update region that intersects
the scrolling area. */
CopyRgn(( (WindowPeek)win->w )->updateRgn, ur);
/* portBits.bounds is the screen in local coordinates! */
left= win->w->portBits.bounds.left;
top= win->w->portBits.bounds.top;
OffsetRgn(ur, left, top); /* Global to Local */
RectRgn(rgn, pr);
SectRgn(rgn, ur, ur);
if (!EmptyRgn(ur)) {
ValidRgn(ur);
OffsetRgn(ur, dh, dv);
SectRgn(rgn, ur, ur);
InvalRgn(ur);
}
DisposeRgn(ur);
}
/* ScrollRect seems to work only in normal mode */
ForeColor(blackColor);
BackColor(whiteColor);
ScrollRect(pr, dh, dv, rgn);
ForeColor((short)win->fgcolor);
BackColor((short)win->bgcolor);
InvalRgn(rgn);
DisposeRgn(rgn);
}
/* Internal version of wupdate -- also used from event.c */
void
_wupdate(win, pr)
WINDOW *win;
Rect *pr;
{
RgnHandle rgn= NewRgn();
SetPort(win->w);
rmcaret(win);
BeginUpdate(win->w);
EraseRect(&win->w->portRect);
_wgrowicon(win);
DrawControls(win->w);
getwinrect(win, pr);
RectRgn(rgn, pr);
SectRgn(rgn, win->w->visRgn, rgn);
*pr= (*rgn)->rgnBBox;
OffsetRect(pr, win->orgh, win->orgv);
if (win->drawproc != NULL && !EmptyRect(pr)) {
wbegindrawing(win);
(*win->drawproc)(win, pr->left, pr->top, pr->right, pr->bottom);
wenddrawing(win);
}
EndUpdate(win->w);
DisposeRgn(rgn);
}
/* Process an update event -- call the window's draw procedure. */
/* XXX This function shouldn't be in the stdwin spec (why was it ever?) */
void
wupdate(win)
WINDOW *win;
{
if (win->drawproc != NULL) {
Rect r;
_wupdate(win, &r);
}
}
void
wbegindrawing(win)
WINDOW *win;
{
Rect r;
if (drawing != NULL) {
dprintf("warning: recursive call to wbegindrawing");
/* Fix it */
wenddrawing(drawing);
}
if (win == NULL) {
dprintf("warning: wbegindrawing(NULL) ignored");
return;
}
drawing= win;
SetPort(win->w);
SetOrigin(win->orgh, win->orgv);
rmcaret(win);
getwinrect(win, &r);
ClipRect(&r);
PenNormal();
wgettextattr(&drawsaveattr);
wsettextattr(&win->attr);
save_fgcolor = _w_fgcolor;
save_bgcolor = _w_bgcolor;
_w_fgcolor = win->fgcolor;
_w_bgcolor = win->bgcolor;
_w_usefgcolor(_w_fgcolor);
_w_usebgcolor(_w_bgcolor);
}
void
wenddrawing(win)
WINDOW *win;
{
Rect r;
if (drawing == NULL) {
dprintf("warning: wenddrawing ignored while not drawing");
return;
}
if (drawing != win) {
dprintf("warning: wenddrawing ignored for wrong window");
return;
}
_w_fgcolor = save_fgcolor;
_w_bgcolor = save_bgcolor;
_w_usefgcolor(win->fgcolor);
_w_usebgcolor(win->bgcolor);
SetOrigin(0, 0);
SetRect(&r, -32000, -32000, 32000, 32000);
ClipRect(&r);
wsettextattr(&drawsaveattr);
drawing= NULL;
}
/* Get the current text attributes of a GrafPort. */
static void
getwattr(port, attr)
GrafPtr port;
TEXTATTR *attr;
{
SetPort(port); /* XXX Is this necessary to validate txFont etc.? */
attr->font= port->txFont;
attr->style= port->txFace;
attr->size= port->txSize;
}
/* Start using the given text attributes in the current grafport. */
static void
setwattr(attr)
TEXTATTR *attr;
{
TextFont(attr->font);
TextFace(attr->style & ~TX_INVERSE);
TextSize(attr->size);
}
/* Get font info and baseline from current GrafPort */
static void
getfinfo()
{
FontInfo finfo;
GetFontInfo(&finfo);
baseline= finfo.ascent + finfo.leading;
lineheight= baseline + finfo.descent;
}
/* Initialize 'wattr'. Uses the screen's grafport. */
int _w_font= applFont;
int _w_size= 9;
void
initwattr()
{
TEXTATTR saveattr;
SetPort(screen);
getwattr(screen, &saveattr);
TextFont(_w_font);
TextSize(_w_size);
getwattr(screen, &wattr);
getfinfo();
setwattr(&saveattr);
}
/* TEXT ATTRIBUTES. */
void
wgettextattr(attr)
TEXTATTR *attr;
{
*attr= wattr;
}
void
wsettextattr(attr)
TEXTATTR *attr;
{
wattr= *attr;
if (drawing != NULL) {
setwattr(attr);
getfinfo();
}
}
void
wgetwintextattr(win, attr)
WINDOW *win;
TEXTATTR *attr;
{
*attr= win->attr;
}
void
wsetwintextattr(win, attr)
WINDOW *win;
TEXTATTR *attr;
{
win->attr= *attr;
if (drawing != NULL)
dprintf("warning: wsetwintextattr called while drawing");
}
char **
wlistfontnames(pat, plen)
char *pat;
int *plen;
{
/* XXX not yet implemented */
*plen = 0;
return NULL;
}
int
wsetfont(fontname)
char *fontname;
{
int ret = 1;
if (fontname == NULL || *fontname == EOS)
wattr.font= _w_font;
else {
short fnum= 0;
GetFNum(PSTRING(fontname), &fnum);
if (fnum == 0) {
dprintf("can't find font %s", fontname);
ret = 0;
}
wattr.font= fnum;
}
if (drawing != NULL) {
TextFont(wattr.font);
getfinfo();
}
return ret;
}
void
wsetsize(size)
int size;
{
wattr.size= size;
if (drawing != NULL) {
TextSize(size);
getfinfo();
}
}
void
wsetstyle(face)
Style face;
{
wattr.style= face;
if (drawing != NULL) {
TextFace(face & ~TX_INVERSE);
getfinfo();
}
}
void
wsetplain()
{
wsetstyle(0);
}
void
wsetinverse()
{
wattr.style |= TX_INVERSE;
}
void
wsetbold()
{
wsetstyle(bold);
}
void
wsetitalic()
{
wsetstyle(italic);
}
void
wsetbolditalic()
{
wsetstyle(bold|italic);
}
void
wsetunderline()
{
wsetstyle(underline);
}
void
wsethilite()
{
wsetstyle(TX_INVERSE);
}
/* TEXT MEASURING. */
int
wlineheight()
{
if (drawing == NULL) {
TEXTATTR saveattr;
getwattr(screen, &saveattr);
setwattr(&wattr);
getfinfo();
setwattr(&saveattr);
}
return lineheight;
}
int
wbaseline()
{
if (drawing == NULL)
(void) wlineheight();
return baseline;
}
int
wtextwidth(str, len)
char *str;
int len;
{
TEXTATTR saveattr;
int width;
if (drawing == NULL) {
getwattr(screen, &saveattr);
setwattr(&wattr);
}
if (len < 0)
len= strlen(str);
width= TextWidth(str, 0, len);
if (drawing == NULL)
setwattr(&saveattr);
return width;
}
int
wcharwidth(c)
int c;
{
char cbuf[1];
cbuf[0]= c;
return wtextwidth(cbuf, 1);
}
/* TEXT DRAWING. */
void
wdrawtext(h, v, str, len)
int h, v;
char *str;
int len;
{
Point pen;
if (len < 0)
len= strlen(str);
MoveTo(h, v + baseline);
DrawText(str, 0, len);
GetPen(&pen);
if (wattr.style & TX_INVERSE) {
Rect r;
SetRect(&r, h, v, pen.h, v + lineheight);
InvertRect(&r);
}
}
void
wdrawchar(h, v, c)
int h, v;
int c;
{
if ((wattr.style & TX_INVERSE) == 0) {
/* Attempt to optimize for appls. like dpv */
MoveTo(h, v + baseline);
DrawChar(c);
}
else {
char cbuf[1];
cbuf[0]= c;
wdrawtext(h, v, cbuf, 1);
}
}
/* COORDINATE CONVERSIONS ETC. */
/* Create a rect in current window coordinates (as for getwinrect)
from a rectangle given in document coordinates.
This works both while drawing and while not drawing.
The resulting rectangle is clipped to the winrect. */
void
makerect(win, pr, left, top, right, bottom)
WINDOW *win;
Rect *pr;
int left, top, right, bottom;
{
Rect r;
SetRect(pr, left, top, right, bottom);
if (!drawing)
OffsetRect(pr, - win->orgh, - win->orgv);
getwinrect(win, &r);
(void) SectRect(&r, pr, pr);
}
/* Retrieve the 'winrect', i.e., the contents area exclusive
of the scroll bars and grow icon.
Coordinates are in window coordinates, i.e.,
the origin is (0, 0) outside w{begin,end}drawing,
but (win->orgh, win->orgv) between calls to these routines. */
void
getwinrect(win, pr)
WINDOW *win;
Rect *pr;
{
*pr= win->w->portRect;
if (win->vbar != NULL)
pr->right -= BAR;
if (win->hbar != NULL)
pr->bottom -= BAR;
}
/* ACTUAL DRAW ROUTINES. */
void
wdrawline(h1, v1, h2, v2)
{
MoveTo(h1, v1);
Line(h2-h1, v2-v1);
}
void
wxorline(h1, v1, h2, v2)
{
MoveTo(h1, v1);
PenMode(patXor);
Line(h2-h1, v2-v1);
PenNormal();
}
void
wdrawbox(left, top, right, bottom)
int left, top, right, bottom;
{
Rect r;
SetRect(&r, left, top, right, bottom);
FrameRect(&r);
}
void
werase(left, top, right, bottom)
int left, top, right, bottom;
{
Rect r;
SetRect(&r, left, top, right, bottom);
EraseRect(&r);
}
void
winvert(left, top, right, bottom)
int left, top, right, bottom;
{
Rect r;
SetRect(&r, left, top, right, bottom);
InvertRect(&r);
}
void
wpaint(left, top, right, bottom)
int left, top, right, bottom;
{
Rect r;
SetRect(&r, left, top, right, bottom);
FillRect(&r, CONSTPATCAST drawing->w->pnPat);
}
void
wshade(left, top, right, bottom, perc)
int left, top, right, bottom;
int perc;
{
Rect r;
PatPtr p;
perc= (perc + 12)/25;
CLIPMIN(perc, 0);
switch (perc) {
case 0: p = &pat0; break;
case 1: p = &pat25; break;
case 2: p = &pat50; break;
case 3: p = &pat75; break;
default: p = &pat100; break;
}
SetRect(&r, left, top, right, bottom);
FillRect(&r, (ConstPatternParam)p);
}
void
wdrawcircle(h, v, radius)
int h, v;
int radius;
{
Rect r;
SetRect(&r, h-radius, v-radius, h+radius, v+radius);
FrameOval(&r);
}
void
wfillcircle(h, v, radius)
int h, v;
int radius;
{
Rect r;
SetRect(&r, h-radius, v-radius, h+radius, v+radius);
FillOval(&r, CONSTPATCAST drawing->w->pnPat);
}
void
wxorcircle(h, v, radius)
int h, v;
int radius;
{
Rect r;
SetRect(&r, h-radius, v-radius, h+radius, v+radius);
InvertOval(&r);
}
/* Draw counterclockwise elliptical arc.
h, v are center; hrad, vrad are half axes; ang1 and ang2 are start
and stop angles in degrees, with respect to 3 o'clock. */
void
wdrawelarc(h, v, hrad, vrad, ang1, ang2)
{
Rect r;
SetRect(&r, h-hrad, v-vrad, h+hrad, v+vrad);
FrameArc(&r, 90-ang1, ang1-ang2);
}
/* Fill an elliptical arc */
void
wfillelarc(h, v, hrad, vrad, ang1, ang2)
{
Rect r;
SetRect(&r, h-hrad, v-vrad, h+hrad, v+vrad);
FillArc(&r, 90-ang1, ang1-ang2, CONSTPATCAST drawing->w->pnPat);
}
/* Invert an elliptical arc */
void
wxorelarc(h, v, hrad, vrad, ang1, ang2)
{
Rect r;
SetRect(&r, h-hrad, v-vrad, h+hrad, v+vrad);
InvertArc(&r, 90-ang1, ang1-ang2);
}
/* Draw a polyline of n-1 connected segments (not necessarily closed).
This means n points. Points are given as an array of POINTs. */
void
wdrawpoly(n, points)
int n;
POINT *points;
{
if (--n > 0) {
MoveTo(points[0].h, points[0].v);
do {
points++;
LineTo(points[0].h, points[0].v);
} while (--n > 0);
}
}
/* Fill a polygon of n points */
void
wfillpoly(n, points)
int n;
POINT *points;
{
PolyHandle ph = OpenPoly();
wdrawpoly(n, points);
ClosePoly();
FillPoly(ph, CONSTPATCAST drawing->w->pnPat);
DisposHandle((Handle)ph);
}
/* Invert a polygon of n points */
void
wxorpoly(n, points)
int n;
POINT *points;
{
PolyHandle ph = OpenPoly();
wdrawpoly(n, points);
ClosePoly();
InvertPoly(ph);
DisposHandle((Handle)ph);
}
/* CLIPPING */
void
wcliprect(left, top, right, bottom)
int left, top, right, bottom;
{
Rect r1, r2;
SetRect(&r1, left, top, right, bottom);
getwinrect(drawing, &r2);
SectRect(&r1, &r2, /*dst:*/ &r2);
ClipRect(&r2);
}
void
wnoclip()
{
Rect r;
getwinrect(drawing, &r);
ClipRect(&r);
}
/* COLOR */
COLOR
wgetfgcolor()
{
return _w_fgcolor;
}
COLOR
wgetbgcolor()
{
return _w_bgcolor;
}
void
wsetfgcolor(color)
COLOR color;
{
_w_fgcolor = color;
if (drawing)
_w_usefgcolor(color);
}
void
wsetbgcolor(color)
COLOR color;
{
_w_bgcolor = color;
if (drawing)
_w_usebgcolor(color);
}
void
_w_usefgcolor(color)
COLOR color;
{
ForeColor((short)color);
switch (((color >> 16) + 32) / 64) {
case 0:
PenPat(CONSTPATCAST pat100);
break;
case 1:
PenPat(CONSTPATCAST pat75);
break;
case 2:
PenPat(CONSTPATCAST pat50);
break;
case 3:
PenPat(CONSTPATCAST pat25);
break;
case 4:
PenPat(CONSTPATCAST pat0);
break;
}
}
void
_w_usebgcolor(color)
COLOR color;
{
BackColor((short)color);
}